package com.easy.frame.common.process.core.service;

import com.easy.frame.common.process.entity.template.Process;
import com.easy.frame.common.process.entity.template.ProcessCondition;
import com.easy.frame.common.process.entity.template.ProcessNode;
import com.easy.frame.common.process.entity.template.dto.ProcessAddDetailDTO;
import com.easy.frame.common.process.util.mapping.ProcessBizMapping;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

/**
 * 流程业务接口
 *
 * @author zzf
 * @date 2021/3/29 14:33
 */
public interface IProcessBizService {

    /**
     * 添加流程
     *
     * @param processAddDetailDTO
     * @return
     */
    @Transactional
    default Process add(ProcessAddDetailDTO processAddDetailDTO) {
        // 再添加之前可以做一些合法性校验

        Process process = ProcessBizMapping.INSTANCE.process(processAddDetailDTO);
        addProcess(process);

        // 这里最重要的是将前端的随机ID改成DB中真实ID，同时还需要保证其对应关系不变。
        // 1、一种方式是通过从最后一个节点倒推，因为最后的节点的nextNodeId=-1，
        //      然后根据node的prevNodeId / condition的nextNodeId 一个个倒推即可。
        // 2、这里我选择第二种，比较无脑的，通过map记录前后id，先全部添加完再全部重新改一遍
        Map<Long, ProcessNode> nodeMap = new HashMap<>();

        processAddDetailDTO.getNodeList()
                .forEach(nodeAddDTO -> {
                    ProcessNode node = ProcessBizMapping.INSTANCE.node(nodeAddDTO);
                    node.setProcessId(process.getId());
                    Long tempId = node.getId();
                    addProcessNode(node);
                    nodeMap.put(tempId, node);
                });

        processAddDetailDTO.getConditionList()
                .forEach(conditionAddDTO -> {
                    ProcessCondition condition = ProcessBizMapping.INSTANCE.condition(conditionAddDTO);
                    condition.setProcessId(process.getId());

                    condition.setPrevNodeId(nodeMap.get(condition.getPrevNodeId()).getId());
                    condition.setNextNodeId(nodeMap.get(condition.getNextNodeId()).getId());

                    addProcessCondition(condition);
                });


        nodeMap.forEach((oldId, node) -> {
            node.setNextNodeId(nodeMap.get(node.getNextNodeId()).getId());
            node.setPrevNodeId(nodeMap.get(node.getPrevNodeId()).getId());
            modifyProcessNodeById(node);
        });

        return process;
    }

    /**
     * 添加流程
     *
     * @param process 流程对象
     */
    void addProcess(Process process);

    /**
     * 添加流程条件
     *
     * @param processCondition 流程条件对象
     */
    void addProcessCondition(ProcessCondition processCondition);

    /**
     * 添加流程节点
     *
     * @param processNode 流程节点对象
     */
    void addProcessNode(ProcessNode processNode);

    /**
     * 根据ID修改流程节点对象
     *
     * @param processNode 流程节点对象
     */
    void modifyProcessNodeById(ProcessNode processNode);
}
